#include <nxos.h>

#define TEST_THREAD_PIPE 0
#define TEST_PROC_NAMED_PIPE 0
#define TEST_PROC_PIPE 0
#define TEST_FILE_PIPE 1

NX_U32 SubThread(void *arg)
{
    char buf[32];

    NX_Solt pipe;
    NX_Size nrecv;

    NX_Printf("SubThread running\n");

    pipe = NX_PipeConnect("mypipe");

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("connect create failed!\n");
        return NX_ErrorGet();
    }

    NX_MemSet(buf, 0, 32);
    nrecv = NX_PipeRecv(pipe, buf, 32);
    NX_Printf("pipe nrecv: %d, data: %s\n", nrecv, buf);

    NX_SoltClose(pipe);

    return 0;
}

NX_Error ThreadPipe(void)
{
    NX_Solt pipe, thread;
        
    thread = NX_ThreadCreate(NX_NULL, SubThread, NX_NULL, 0);
    if (thread == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("pipe thread failed!\n");
        return NX_ErrorGet();
    }
    
    pipe = NX_PipeCreate("mypipe", 256, NX_PIPE_SEND);

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("pipe create failed!\n");
        return NX_ErrorGet();
    }

    char *str = "hello, pipe!\n";

    NX_Size nsend = NX_PipeSend(pipe, str, NX_StrLen(str));
    NX_Printf("pipe nsend: %d\n", nsend);
    NX_PipeDisconnect(pipe);

    NX_ThreadWait(thread, NX_NULL);

    NX_SoltClose(pipe);

    return NX_EOK;
}

NX_Error ProcNamedPipeChild(void)
{
    char buf[32];

    NX_Solt pipe;
    NX_Size nrecv;

    pipe = NX_PipeConnect("mypipe");

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("connect create failed!\n");
        return NX_ErrorGet();
    }

    NX_MemSet(buf, 0, 32);
    nrecv = NX_PipeRecv(pipe, buf, 32);
    NX_Printf("pipe nrecv: %d, data: %s\n", nrecv, buf);

    NX_SoltClose(pipe);

    return 0;
}

NX_Error ProcNamedPipeParent(void)
{
    NX_Solt pipe;

    pipe = NX_PipeCreate("mypipe", 256, NX_PIPE_SEND);

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("pipe create failed!\n");
        return NX_ErrorGet();
    }

    NX_ProcessLaunch("/System/Applications/TestNxbase.xapp", 0, NX_NULL, "/System/Applications/TestNxbase.xapp pipe child", NX_NULL);

    char *str = "hello, pipe!\n";

    NX_Size nsend = NX_PipeSend(pipe, str, NX_StrLen(str));
    NX_Printf("pipe nsend: %d\n", nsend);
    NX_PipeDisconnect(pipe);

    // sleep 1s
    NX_ThreadSleep(1000);

    NX_SoltClose(pipe);

    return NX_EOK;
}

NX_Error ProcNamedPipe(char *cmdline)
{
    char *cmd[64];
    int argc;
    int isChild = 0;
    
    NX_MemZero(cmd, sizeof(cmd));
    argc = NX_CmdToArray(cmdline, cmd, 64);
    
    if (argc > 1)
    {
        isChild = 1;
    }

    NX_Printf("is Child:%d\n", isChild);
    
    if (!isChild)
    {
        return ProcNamedPipeParent();
    }
    else
    {
        return ProcNamedPipeChild();
    }
}

NX_Error ProcPipeChild(void)
{
    char buf[32];

    NX_Printf("child thread solt:%d, tid:%d", NX_ThreadGetCurrent(), NX_ThreadGetCurrentId());

    NX_Solt pipe;
    NX_Size nrecv;

    pipe = 0; // 0 = stdin pipe

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("connect create failed!\n");
        return NX_ErrorGet();
    }

    NX_MemSet(buf, 0, 32);
    nrecv = NX_PipeRecv(pipe, buf, 32);
    NX_Printf("pipe nrecv: %d, data: %s\n", nrecv, buf);

    NX_SoltClose(pipe);

    return 0;
}

NX_Error ProcPipeParent(void)
{
    NX_Solt pipe, child;

    pipe = NX_PipeCreate(NX_NULL, 256, NX_PIPE_SEND);

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("pipe create failed!\n");
        return NX_ErrorGet();
    }

    child = NX_ProcessLaunch("/System/Applications/TestNxbase.xapp", NX_THREAD_CREATE_SUSPEND, NX_NULL, "/System/Applications/TestNxbase.xapp pipe child", NX_NULL);
    if (child == NX_SOLT_INVALID_VALUE)
    {
        NX_SoltClose(pipe);
        return NX_ErrorGet();
    }

    NX_Solt newPipeSolt = NX_SoltCopyTo(child, pipe, 0);
    NX_Printf("COPY pipe solt %d to child %d, solt is %d\n", pipe, child, newPipeSolt);

    NX_ThreadResume(child);
    
    char *str = "hello, pipe!\n";

    NX_Size nsend = NX_PipeSend(pipe, str, NX_StrLen(str));
    NX_Printf("pipe nsend: %d\n", nsend);
    NX_PipeDisconnect(pipe);

    // sleep 1s
    NX_ThreadSleep(1000);

    NX_SoltClose(pipe);

    return NX_EOK;
}

NX_Error ProcPipe(char *cmdline)
{
    char *cmd[64];
    int argc;
    int isChild = 0;
    
    NX_MemZero(cmd, sizeof(cmd));
    argc = NX_CmdToArray(cmdline, cmd, 64);
    
    if (argc > 1)
    {
        isChild = 1;
    }

    NX_Printf("is Child:%d\n", isChild);
    
    if (!isChild)
    {
        return ProcPipeParent();
    }
    else
    {
        return ProcPipeChild();
    }
}

NX_Error FilePipeChild(void)
{
    char buf[32];

    NX_Printf("child thread solt:%d, tid:%d", NX_ThreadGetCurrent(), NX_ThreadGetCurrentId());

    NX_Solt pipe;
    NX_Size nrecv;

    pipe = 0; // 0 = stdin pipe

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("connect create failed!\n");
        return NX_ErrorGet();
    }

    NX_MemSet(buf, 0, 32);
    nrecv = NX_FileRead(pipe, buf, 32);
    NX_Printf("pipe nrecv: %d, data: %s\n", nrecv, buf);

    NX_SoltClose(pipe);

    return 0;
}

NX_Error FilePipeParent(void)
{
    NX_Solt pipe, child;

    pipe = NX_PipeCreate(NX_NULL, 8, NX_PIPE_SEND);

    if (pipe == NX_SOLT_INVALID_VALUE)
    {
        NX_Printf("pipe create failed!\n");
        return NX_ErrorGet();
    }

    child = NX_ProcessLaunch("/System/Applications/TestNxbase.xapp", NX_THREAD_CREATE_SUSPEND, NX_NULL, "/System/Applications/TestNxbase.xapp pipe child", NX_NULL);
    if (child == NX_SOLT_INVALID_VALUE)
    {
        NX_SoltClose(pipe);
        return NX_ErrorGet();
    }

    NX_Solt newPipeSolt = NX_SoltCopyTo(child, pipe, 0);
    NX_Printf("COPY pipe solt %d to child %d, solt is %d\n", pipe, child, newPipeSolt);

    NX_ThreadResume(child);
    
    char *str = "hello, pipe!\n";

    NX_Size nsend = NX_FileWrite(pipe, str, NX_StrLen(str));
    NX_Printf("pipe nsend: %d\n", nsend);

    NX_SoltClose(pipe);

    return NX_EOK;
}

NX_Error FilePipe(char *cmdline)
{
    char *cmd[64];
    int argc;
    int isChild = 0;
    
    NX_MemZero(cmd, sizeof(cmd));
    argc = NX_CmdToArray(cmdline, cmd, 64);
    
    if (argc > 1)
    {
        isChild = 1;
    }

    NX_Printf("is Child:%d\n", isChild);
    
    if (!isChild)
    {
        return FilePipeParent();
    }
    else
    {
        return FilePipeChild();
    }
}

NX_Error TEST_Pipe(char *cmdline)
{
#if TEST_THREAD_PIPE == 1
    return ThreadPipe();
#endif

#if TEST_PROC_NAMED_PIPE == 1
    return ProcNamedPipe(cmdline);
#endif

#if TEST_PROC_PIPE == 1
    return ProcPipe(cmdline);
#endif

#if TEST_FILE_PIPE == 1
    return FilePipe(cmdline);
#endif
}
